home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xmbase-grok-1.2
/
dbfile.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-25
|
11KB
|
422 lines
/*
* read and write database files.
*
* write_dbase(form, path) write dbase
* read_dbase(form, path) read dbase into empty dbase struct
*/
#include "config.h"
#include <X11/Xos.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <assert.h>
#include <signal.h>
#ifdef DIRECT
#include <sys/dir.h>
#define dirent direct
#else
#include <dirent.h>
#endif
#include <Xm/Xm.h>
#include "grok.h"
#include "form.h"
#include "proto.h"
#define R_SEP '\n' /* row (card) separator */
#define ESC '\\' /* treat next char literally */
extern int errno;
extern char *progname; /* argv[0] */
extern Widget toplevel; /* top-level shell for icon name */
/*
* If the print spooler dies for some reason, print a message. Don't let
* grok die because of the broken pipe signal.
*/
static void broken_pipe_handler(int sig)
{
create_error_popup(toplevel, 0,
"Procedural script aborted with signal %d\n", sig);
signal(SIGPIPE, SIG_IGN);
}
/*
* Write the database and all the items in it. The <path> is from the
* forms <dbase> field. Both the database and the form will be stored
* in a CARD structure; both are required to access cards. If the
* database is procedural, open a pipe to the database process and add
* -r option.
* Returns FALSE if the file could not be written.
*/
static BOOL writefile(DBASE *, FORM *, int);
BOOL write_dbase(
DBASE *dbase, /* form and items to write */
FORM *form, /* contains column delimiter */
BOOL force) /* write even if not modified*/
{
int s; /* section index */
BOOL ok = TRUE;
if (dbase->nsects == 1 && (dbase->modified || force))
ok = writefile(dbase, form, 0);
else
for (s=0; s < dbase->nsects; s++)
if (dbase->sect[s].modified &&
(!dbase->sect[s].rdonly || force))
ok &= writefile(dbase, form, s);
return(ok);
}
static BOOL writefile(
DBASE *dbase, /* form and items to write */
FORM *form, /* contains column delimiter */
int nsect) /* section to write */
{
SECTION *sect; /* section to write */
char *path; /* file to write list to */
FILE *fp; /* open file */
int r, c; /* row and column counters */
int hicol; /* # of columns of card -1 */
char *value; /* converted data to write */
char buf[40]; /* for date/time conversion */
register ITEM *item; /* item describing value */
register int i; /* index of item */
register char *p; /* string copy pointer */
sect = &dbase->sect[nsect];
path = sect->path ? sect->path : form->dbase;
if (!path || !*path) {
create_error_popup(toplevel, 0,
"Database has no name, cannot save to disk");
return(FALSE);
}
path = resolve_tilde(path, 0);
if (form->proc) {
char cmd[1024];
sprintf(cmd, "%s -w %s", path, form->name);
if (!(fp = popen(cmd, "w"))) {
create_error_popup(toplevel, errno,
"Failed to run shell script %s", cmd);
return(FALSE);
}
} else
if (!(fp = fopen(path, "w"))) {
create_error_popup(toplevel, errno,
"Failed to create database file %s", path);
return(FALSE);
}
for (r=0; r < dbase->nrows; r++) {
if (nsect != dbase->row[r]->section)
continue;
for (hicol=dbase->row[r]->ncolumns-1; hicol > 0; hicol--)
if (dbase_get(dbase, r, hicol))
break;
for (c=0; c <= hicol; c++) {
if (value = dbase_get(dbase, r, c)) {
for (i=form->nitems-1; i >= 0; i--) {
item = form->items[i];
if (item->column == c)
break;
}
if (i >= 0 && item->type == IT_TIME) {
long secs = atoi(value);
switch(item->timefmt) {
case T_DATE:
sprintf(value = buf, "%s",
mkdatestring(secs));
break;
case T_TIME:
sprintf(value = buf, "%s",
mktimestring(secs, 0));
break;
case T_DATETIME:
sprintf(value = buf, "%s %s",
mkdatestring(secs),
mktimestring(secs, 0));
break;
case T_DURATION:
sprintf(value = buf, "%s",
mktimestring(secs, 1));
break;
}
}
for (p=value; *p; p++) {
if (*p == R_SEP ||
*p == form->cdelim ||
*p == ESC)
fputc(ESC, fp);
fputc(*p, fp);
}
}
if (c < hicol)
fputc(form->cdelim, fp);
}
fputc(R_SEP, fp);
}
if (form->proc)
if (pclose(fp)) {
create_error_popup(toplevel, errno,
"%s:\nfailed to create database", path);
return(FALSE);
} else
return(TRUE);
else
fclose(fp);
if (sect)
sect->modified = FALSE;
dbase->modified = FALSE;
sect->mtime = time(0);
print_info_line();
return(TRUE);
}
/*
* Read a database from a file. The database must be empty (just created
* with dbase_create()). Returns FALSE if the file could not be read.
* Print a warning if the database is supposed to be writable but isn't.
*
* This works by first reading in fields, allocating one string for each.
* The strings are stored in a long list. Escaped separators are resolved.
* Row separators are stored as null pointers in the list. When the end
* of the file is reached, the number of rows and columns is known, and
* the pointers in the list are put in the right places of the dbase array.
*/
#define LCHUNK 4096 /* alloc this many new list ptrs */
#define BCHUNK 1024 /* alloc this many new chars for item */
static BOOL find_db_file (DBASE *, FORM *, char *);
static BOOL read_dir_or_file (DBASE *, FORM *, char *);
static BOOL read_file (DBASE *, FORM *, char *, time_t);
BOOL read_dbase(
DBASE *dbase, /* form and items to write */
FORM *form, /* contains column delimiter */
char *path) /* file to read list from */
{
char pathbuf[1024]; /* file name with path */
BOOL ret; /* return code, FALSE=error */
if (!path || !*path) {
create_error_popup(toplevel, 0,
"Database has no name, cannot read from disk");
return(FALSE);
}
dbase_delete(dbase);
init_variables();
if (*path != '/' && *path != '~' && form->path) {
char *p;
strcpy(pathbuf, form->path);
if (p = strrchr(pathbuf, '/')) {
strcpy(p+1, path);
path = pathbuf;
}
}
if (!(ret = find_db_file(dbase, form, path)))
create_error_popup(toplevel, 0, "Failed to read %s", path);
if (!dbase->nsects) {
if (!(dbase->sect = malloc(sizeof(SECTION)))) {
fprintf(stderr,
"grok: no memory for section, cannot continue.");
exit(1);
}
mybzero(dbase->sect, sizeof(SECTION));
dbase->nsects = 1;
}
dbase->currsect = -1;
dbase->modified = FALSE;
print_info_line();
return(ret);
}
/*
* read both path.db and path, in that order. Return FALSE if both failed.
*/
static BOOL find_db_file(
DBASE *dbase, /* form and items to write */
FORM *form, /* contains column delimiter */
char *path) /* file to read list from */
{
char pathbuf[1024]; /* file name with path */
int nread = 0; /* # of successful reads */
sprintf(pathbuf, "%s.db", path);
if (!access(pathbuf, F_OK))
nread += read_dir_or_file(dbase, form, pathbuf);
if (!access(path, F_OK))
nread += read_dir_or_file(dbase, form, path);
return(nread > 0);
}
/*
* read path. If it's a directory, recurse. Return FALSE if nothing was found.
*/
static BOOL read_dir_or_file(
DBASE *dbase, /* form and items to write */
FORM *form, /* contains column delimiter */
char *path) /* file to read list from */
{
char pathbuf[1024]; /* file name with path */
struct stat statbuf; /* is path a directory? */
DIR *dir; /* open directory file */
struct dirent *dp; /* one directory entry */
int nfiles = 0; /* # of files in directory */
if (stat(path, &statbuf))
return(FALSE);
if (!(statbuf.st_mode & S_IFDIR))
return(read_file(dbase, form, path, statbuf.st_mtime));
if (!(dir = opendir(path)))
return(FALSE);
while (dp = readdir(dir))
if (*dp->d_name != '.') {
sprintf(pathbuf, "%s/%s", path, dp->d_name);
nfiles += read_dir_or_file(dbase, form, pathbuf);
}
(void)closedir(dir);
dbase->havesects = TRUE;
return(nfiles > 0);
}
/*
* read one plain file and append to dbase section list. Return FALSE on error.
*/
static BOOL read_file(
DBASE *dbase, /* form and items to write */
FORM *form, /* contains column delimiter */
char *path, /* file to read list from */
time_t mtime) /* file modification time */
{
SECTION *sect; /* new section */
FILE *fp; /* open file */
int nc = 0; /* size of curr line */
int col = 0; /* current column being added*/
int row = -1; /* current row being added */
register char *buf, *p; /* buffer for one item */
register int bindex = 0; /* next free byte in buf */
int bsize; /* size of buf in bytes */
char c, c0; /* next char from file */
BOOL error; /* in TRUE, abort */
ITEM *item; /* for time/date conversion */
int i;
/* step 1: open file */
signal(SIGPIPE, broken_pipe_handler);
if (form->proc) {
char cmd[1024];
path = resolve_tilde(path, 0);
sprintf(cmd, "%s -r %s", path, form->name);
if (!(fp = popen(cmd, "r")))
return(FALSE);
} else {
path = resolve_tilde(path, "db");
if (!(fp = fopen(path, "r")))
return(FALSE);
}
/* step 2: new sectn */
i = (dbase->nsects+1) * sizeof(SECTION);
if (!(sect = dbase->sect ? realloc(dbase->sect, i) : malloc(i))) {
create_error_popup(toplevel, errno,
"No memory for section %s", path);
form->proc ? pclose(fp) : fclose(fp);
return(FALSE);
}
dbase->sect = sect;
mybzero(sect = &dbase->sect[dbase->nsects], sizeof(SECTION));
dbase->currsect = dbase->nsects++;
sect->mtime = mtime;
sect->path = mystrdup(path);
/* step 3: read list */
buf = (char *)malloc((bsize = BCHUNK) * sizeof(char));
error = !buf;
while (!error) { /* read file:*/
c = c0 = fgetc(fp);
if (!feof(fp) && c == ESC)
c = fgetc(fp);
/* end of str*/
if (feof(fp) || c0 == form->cdelim || c0 == R_SEP) {
if (!nc) {
if (c0 == form->cdelim) col++;
if (feof(fp)) break;
else continue;
}
buf[bindex] = 0; /* next col */
/* .. date? */
for (i=-1, p=buf; *p; p++)
if (*p=='.' || *p==':' || *p=='/') {
for (i=form->nitems-1; i >= 0; i--) {
item = form->items[i];
if (item->column == col)
break;
}
break;
}
if (i >= 0 && item->type == IT_TIME) /* .. -> int */
switch(item->timefmt) {
case T_DATE:
sprintf(buf, "%d",
parse_datestring(buf));
break;
case T_TIME:
sprintf(buf, "%d",
parse_timestring(buf, FALSE));
break;
case T_DATETIME:
sprintf(buf, "%d",
parse_datetimestring(buf));
break;
case T_DURATION:
sprintf(buf, "%d",
parse_timestring(buf, TRUE));
}
/* store str */
if (row < 0)
if (error |= !dbase_addrow(&row, dbase))
break;
dbase_put(dbase, row, col++, buf);
bindex = 0;
if (feof(fp) || c0 == R_SEP) { /* next row */
col = nc = 0;
row = -1;
if (feof(fp))
break;
}
} else { /* store char*/
if (bindex+1 >= bsize) {
char *new = (char *)realloc(buf,
(bsize += BCHUNK));
if (error |= !new)
break;
buf = new;
}
buf[bindex++] = c;
nc++;
}
}
/* done. */
free(buf);
error |= form->proc ? !pclose(fp) : !!fclose(fp);
sect->modified = FALSE;
sect->rdonly =
dbase->rdonly = form->proc ? FALSE : !!access(path, W_OK);
if (error)
create_error_popup(toplevel, errno,
"Failed to allocate memory for\ndatabase %s", path);
return(!error);
}